package org.jeecg.modules.wms.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.DateUtils;
import org.jeecg.common.util.oConvertUtils;
import org.springframework.web.multipart.MultipartFile;
import org.jeecg.modules.oms.entity.ProductSalesOrder;
import org.jeecg.modules.oms.service.IProductSalesOrderService;
import org.jeecg.modules.wms.entity.*;
import org.jeecg.modules.wms.mapper.WmsInboundOrderMapper;
import org.jeecg.modules.wms.mapper.WmsMaterialMapper;
import org.jeecg.modules.wms.service.*;
import org.jeecg.modules.wms.vo.SurplusMaterialVO;
import org.jeecg.modules.wms.vo.WmsInboundOrderMaterialVO;
import org.jeecg.modules.wms.vo.WmsInboundOrderVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 入库单服务实现
 */
@Slf4j
@Service
public class WmsInboundOrderServiceImpl extends ServiceImpl<WmsInboundOrderMapper, WmsInboundOrder> implements IWmsInboundOrderService {

    @Autowired
    private IWmsInventoryService inventoryService;

    @Autowired
    private IWmsInboundOrderDetailService detailService;

    @Autowired
    private WmsMaterialMapper materialMapper;

    @Autowired
    private IWmsOutboundService wmsOutboundService;

    @Autowired
    private IWmsOutboundDetailService wmsOutboundDetailService;

    @Autowired
    private IWmsInventoryService wmsInventoryService;

    @Autowired
    private IWmsInventoryHistoryService wmsInventoryHistoryService;

    @Autowired
    private ISurplusMaterialService surplusMaterialService;

    @Autowired
    private IAutoLocationAllocationService autoLocationAllocationService;

    @Autowired
    private IWmsPurchaseOrderService wmsPurchaseOrderService;

    @Autowired
    private IWmsMaterialService wmsMaterialService;

    @Autowired
    private IWmsWarehouseService wmsWarehouseService;

    @Autowired
    private IWmsWarehouseLocationService wmsWarehouseLocationService;

    /**
     * 查询入库单分页列表
     */
    public IPage<WmsInboundOrderVO> queryInboundOrderPageList(Page<WmsInboundOrderVO> page, Map<String, Object> params) {
        // 构建查询条件
        QueryWrapper<WmsInboundOrder> queryWrapper = new QueryWrapper<>();

        // 处理计划入库时间查询（单日期）
        if (params.get("planInboundTime") != null) {
            String planInboundTime = (String) params.get("planInboundTime");
            queryWrapper.apply("DATE_FORMAT(plan_inbound_time, '%Y-%m-%d') = {0}", planInboundTime);
        }

        // 处理实际入库时间查询（单日期）
        if (params.get("actualInboundTime") != null) {
            String actualInboundTime = (String) params.get("actualInboundTime");
            queryWrapper.apply("DATE_FORMAT(actual_inbound_time, '%Y-%m-%d') = {0}", actualInboundTime);
        }

        return baseMapper.queryInboundOrderPageList(page, params);
    }

    @Override
    public WmsInboundOrderVO getInboundOrderById(String id) {
        WmsInboundOrderVO inboundOrderVO = baseMapper.getInboundOrderById(id);
        if (inboundOrderVO != null) {
            // 查询明细列表
            List<WmsInboundOrderDetail> detailList = detailService.listByInboundOrderId(id);
            inboundOrderVO.setDetailList(detailList);
        }
        return inboundOrderVO;
    }

    public WmsInboundOrderVO getInboundOrderByIdAndUpdateBy(String id, String username) {
        WmsInboundOrderVO inboundOrderVO = baseMapper.getInboundOrderById(id);
        if (inboundOrderVO != null) {
            // 查询明细列表
            List<WmsInboundOrderDetail> detailList = detailService.listByInboundOrderIdAndUpdateBy(id, username);
            inboundOrderVO.setDetailList(detailList);
        }
        return inboundOrderVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String createInboundOrder(WmsInboundOrderVO inboundOrder) {
        // 参数校验
        if (inboundOrder == null) {
            throw new JeecgBootException("入库单参数不能为空");
        }

        // 检查是否有物料列表
        List<WmsInboundOrderMaterialVO> materialList = inboundOrder.getMaterialList();
        if (materialList == null || materialList.isEmpty()) {
            throw new JeecgBootException("物料列表不能为空");
        }

        // 保存入库单及其明细
        boolean success = saveInboundOrderWithDetails(inboundOrder);
        if (!success) {
            throw new JeecgBootException("创建入库单失败");
        }

        // 如果是调拨入库单（业务类型13），同时创建调拨出库记录
        if (inboundOrder.getBusinessType() != null && inboundOrder.getBusinessType() == 13) {
            try {
                createTransferOutboundRecord(inboundOrder);
                log.info("调拨入库单创建成功，同时创建了调拨出库记录：{}", inboundOrder.getInboundNo());
            } catch (Exception e) {
                log.error("创建调拨出库记录失败，入库单号：{}", inboundOrder.getInboundNo(), e);
                // 调拨出库记录创建失败不影响入库单创建
            }
        }

        return inboundOrder.getInboundNo();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String createSurplusInboundOrder(WmsInboundOrderVO inboundOrder) {
        // 参数校验
        if (inboundOrder == null) {
            throw new JeecgBootException("入库单参数不能为空");
        }

        // 设置业务类型为余料入库
        inboundOrder.setBusinessType(12);
        inboundOrder.setIsSurplus(true);

        // 检查是否有物料列表
        List<WmsInboundOrderMaterialVO> materialList = inboundOrder.getMaterialList();
        if (materialList == null || materialList.isEmpty()) {
            throw new JeecgBootException("物料列表不能为空");
        }

        // 生成入库单号
        if (StringUtils.isBlank(inboundOrder.getInboundNo())) {
            inboundOrder.setInboundNo(generateInboundNoByBusinessType(inboundOrder.getBusinessType()));
        }

        // 生成业务单号和批次号
        String businessNo = inboundOrder.getBusinessNo();
        String batchNo = inboundOrder.getBatchNo();

        if (StringUtils.isBlank(businessNo) || StringUtils.isBlank(batchNo)) {
            Date now = new Date();
            String dateStr = String.format("%tY%<tm%<td%<tH%<tM%<tS", now);
            String randomNum = String.format("%03d", (int) (Math.random() * 1000));

            // 余料入库业务单号应该是订单编号，这里不自动生成
            // 如果没有传入业务单号，保持为空
            if (StringUtils.isBlank(businessNo)) {
                // 余料入库的业务单号应该是订单编号，由前端传入
                log.debug("余料入库单未设置业务单号（订单编号）");
            }

            // 生成批次号：PC + 年月日 + 4位随机数
            if (StringUtils.isBlank(batchNo)) {
                String batchDateStr = String.format("%tY%<tm%<td", now);
                String batchRandomNum = String.format("%04d", (int) (Math.random() * 10000));
                batchNo = "PC" + batchDateStr + batchRandomNum;
                inboundOrder.setBatchNo(batchNo);
            }
        }

        // 设置入库单状态为待入库
        inboundOrder.setStatus(1);

        // 设置计划入库时间
        if (inboundOrder.getPlanInboundTime() == null) {
            inboundOrder.setPlanInboundTime(new Date());
        }

        // 计算总计划入库数量和总成本
        BigDecimal totalPlanQuantity = BigDecimal.ZERO;
        BigDecimal totalCost = BigDecimal.ZERO;

        for (WmsInboundOrderMaterialVO material : materialList) {
            if (material.getPlanQuantity() != null) {
                totalPlanQuantity = totalPlanQuantity.add(material.getPlanQuantity());
            }

            if (material.getUnitCost() != null && material.getPlanQuantity() != null) {
                BigDecimal cost = material.getUnitCost().multiply(material.getPlanQuantity());
                totalCost = totalCost.add(cost);
            }
        }

        inboundOrder.setTotalPlanQuantity(totalPlanQuantity);
        inboundOrder.setTotalCost(totalCost);

        // 设置创建人和创建时间
        LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        if (loginUser != null) {
            inboundOrder.setCreateBy(loginUser.getUsername());
        }
        inboundOrder.setCreateTime(new Date());

        // 保存入库单
        boolean success = save(inboundOrder);
        if (!success) {
            throw new JeecgBootException("保存余料入库单失败");
        }

        // 保存明细
        saveInboundOrderDetails(inboundOrder, materialList);

        return inboundOrder.getInboundNo();
    }

    /**
     * 保存入库单明细信息
     */
    private void saveInboundOrderDetails(WmsInboundOrderVO inboundOrder, List<WmsInboundOrderMaterialVO> materialList) {
        if (materialList == null || materialList.isEmpty()) {
            return;
        }

        List<WmsInboundOrderDetail> detailList = new ArrayList<>();

        for (WmsInboundOrderMaterialVO material : materialList) {
            WmsInboundOrderDetail detail = new WmsInboundOrderDetail();

            // 设置关联ID
            detail.setInboundOrderId(inboundOrder.getId());

            // 设置物料信息
            detail.setMaterialCode(material.getMaterialCode());
            detail.setMaterialName(material.getMaterialName());
            detail.setMaterialType(String.valueOf(material.getMaterialType()));
            detail.setSpecification(material.getSpecification());
            detail.setColor(material.getColor());
            detail.setUnit(material.getUnit());

            // 设置仓库库位信息
            detail.setPlanWarehouseId(material.getPlanWarehouseId());
            detail.setPlanWarehouseName(material.getPlanWarehouseName());
            detail.setPlanLocationId(material.getPlanLocationId());
            detail.setPlanLocationName(material.getPlanLocationName());

            // 设置数量和成本
            detail.setPlanQuantity(material.getPlanQuantity());
            detail.setUnitCost(material.getUnitCost());

            // 计算总成本
            if (material.getUnitCost() != null && material.getPlanQuantity() != null) {
                BigDecimal itemTotalCost = material.getUnitCost().multiply(material.getPlanQuantity());
                detail.setTotalCost(itemTotalCost);
            }

            // 设置预警值
            detail.setUpperLimit(material.getUpperLimit());
            detail.setLowerLimit(material.getLowerLimit());

            // 设置余料标识
            detail.setIsSurplus(true);

            detailList.add(detail);
        }

        // 批量保存明细
        boolean success = detailService.saveBatch(detailList);
        if (!success) {
            throw new JeecgBootException("保存余料入库单明细失败");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean saveInboundOrderWithDetails(WmsInboundOrderVO inboundOrder) {
        // 参数校验
        if (inboundOrder == null) {
            throw new JeecgBootException("入库单参数不能为空");
        }

        // 检查是否有物料列表
        List<WmsInboundOrderMaterialVO> materialList = inboundOrder.getMaterialList();
        if (materialList == null || materialList.isEmpty()) {
            throw new JeecgBootException("物料列表不能为空");
        }

        // 生成入库单号
        if (StringUtils.isBlank(inboundOrder.getInboundNo())) {
            inboundOrder.setInboundNo(generateInboundNoByBusinessType(inboundOrder.getBusinessType()));
        }

        // 生成批次号
        String batchNo = inboundOrder.getBatchNo();
        if (StringUtils.isBlank(batchNo)) {
            // 生成批次号：业务类型前缀 + 年月日 + 4位随机数
            String prefix;
            switch (inboundOrder.getBusinessType()) {
                case 11:
                    prefix = "CG";
                    break; // 采购入库
                case 12:
                    prefix = "YL";
                    break; // 余料入库
                case 13:
                    prefix = "DB";
                    break; // 调拨入库
                default:
                    prefix = "QT";
                    break; // 其他入库
            }
            String dateStr = String.format("%tY%<tm%<td", new Date());
            String randomNum = String.format("%04d", (int) (Math.random() * 10000));
            batchNo = prefix + dateStr + randomNum;
            inboundOrder.setBatchNo(batchNo);
        }

        // 设置入库单状态为待入库
        inboundOrder.setStatus(1);

        // 设置当前时间为计划入库时间
        if (inboundOrder.getPlanInboundTime() == null) {
            inboundOrder.setPlanInboundTime(new Date());
        }

        // 设置采购入库特有字段
        if (inboundOrder.getBusinessType() != null && inboundOrder.getBusinessType() == 11) {
            // 如果是采购入库，设置采购单号和采购单ID
            if (StringUtils.isNotBlank(inboundOrder.getPurchaseOrderNo())) {
                inboundOrder.setPurchaseOrderNo(inboundOrder.getPurchaseOrderNo());
            }
            if (StringUtils.isNotBlank(inboundOrder.getPurchaseOrderId())) {
                inboundOrder.setPurchaseOrderId(inboundOrder.getPurchaseOrderId());
            }
        }

        // 计算总计划入库数量和总成本
        BigDecimal totalPlanQuantity = BigDecimal.ZERO;
        BigDecimal totalCost = BigDecimal.ZERO;

        for (WmsInboundOrderMaterialVO material : materialList) {
            if (material.getPlanQuantity() != null) {
                totalPlanQuantity = totalPlanQuantity.add(material.getPlanQuantity());

                if (material.getUnitCost() != null) {
                    BigDecimal itemCost = material.getUnitCost().multiply(material.getPlanQuantity());
                    totalCost = totalCost.add(itemCost);
                }
            }
        }

        inboundOrder.setTotalPlanQuantity(totalPlanQuantity);
        inboundOrder.setTotalCost(totalCost);

        // 设置创建人和创建时间
        LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        if (loginUser != null) {
            inboundOrder.setCreateBy(loginUser.getUsername());
        }
        inboundOrder.setCreateTime(new Date());

        // 保存入库单
        boolean success = save(inboundOrder);
        if (!success) {
            throw new JeecgBootException("保存入库单失败");
        }

        // 保存明细
        List<WmsInboundOrderDetail> detailList = new ArrayList<>();

        for (WmsInboundOrderMaterialVO material : materialList) {
            WmsInboundOrderDetail detail = new WmsInboundOrderDetail();

            // 设置关联ID
            detail.setInboundOrderId(inboundOrder.getId());

            // 设置物料信息
            detail.setMaterialCode(material.getMaterialCode());
            detail.setMaterialId(material.getMaterialId());
            detail.setMaterialType(String.valueOf(material.getMaterialType()));
            detail.setMaterialName(material.getMaterialName());
            detail.setSpecification(material.getSpecification());
            detail.setColor(material.getColor());
            detail.setUnit(material.getUnit());

            // 设置仓库库位信息
            detail.setPlanWarehouseId(material.getPlanWarehouseId());
            detail.setPlanWarehouseName(material.getPlanWarehouseName());
            detail.setPlanLocationId(material.getPlanLocationId());
            detail.setPlanLocationName(material.getPlanLocationName());

            // 调拨入库时，设置源仓库和源库位信息
            if (inboundOrder.getBusinessType() == 13) {
                detail.setSourceWarehouseId(material.getSourceWarehouseId());
                detail.setSourceWarehouseName(material.getSourceWarehouseName());
                detail.setSourceLocationId(material.getSourceLocationId());
                detail.setSourceLocationName(material.getSourceLocationName());
                detail.setBatchNo(material.getBatchNo());
            }

            // 设置数量和成本
            detail.setPlanQuantity(material.getPlanQuantity());
            detail.setUnitCost(material.getUnitCost());

            // 计算总成本
            if (material.getUnitCost() != null && material.getPlanQuantity() != null) {
                BigDecimal itemTotalCost = material.getUnitCost().multiply(material.getPlanQuantity());
                detail.setTotalCost(itemTotalCost);
            }

            detailList.add(detail);
        }

        // 批量保存明细
        boolean detailSuccess = detailService.saveBatch(detailList);
        if (!detailSuccess) {
            throw new JeecgBootException("保存入库单明细失败");
        }

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean confirmInbound(String id, String detailId, String actualWarehouseId, String actualLocationId,
                                  BigDecimal actualQuantity, String remark) {
        // 参数校验
        if (StringUtils.isBlank(id)) {
            throw new JeecgBootException("入库单ID不能为空");
        }

        if (StringUtils.isBlank(detailId)) {
            throw new JeecgBootException("入库单明细ID不能为空");
        }

        if (StringUtils.isBlank(actualWarehouseId)) {
            throw new JeecgBootException("实际入库仓库不能为空");
        }

        if (StringUtils.isBlank(actualLocationId)) {
            throw new JeecgBootException("实际入库库位不能为空");
        }

        if (actualQuantity == null || actualQuantity.compareTo(BigDecimal.ZERO) <= 0) {
            throw new JeecgBootException("实际入库数量必须大于0");
        }

        // 查询入库单
        WmsInboundOrder inboundOrder = getById(id);
        if (inboundOrder == null) {
            throw new JeecgBootException("入库单不存在");
        }

        // 校验入库单状态
        if (inboundOrder.getStatus() != 1 && inboundOrder.getStatus() != 3) {
            throw new JeecgBootException("只有待入库或部分入库状态的入库单才能确认入库");
        }

        // 查询入库单明细
        WmsInboundOrderDetail detail = detailService.getById(detailId);
        if (detail == null) {
            throw new JeecgBootException("入库单明细不存在");
        }

        // 更新明细信息
        detail.setActualWarehouseId(actualWarehouseId);
        detail.setActualLocationId(actualLocationId);

        // 判断是否已经有部分入库
        BigDecimal originalActualQuantity = detail.getActualQuantity() == null ? BigDecimal.ZERO : detail.getActualQuantity();
        BigDecimal newActualQuantity = originalActualQuantity.add(actualQuantity);
        detail.setActualQuantity(newActualQuantity);

        // 重新计算总成本
        if (detail.getUnitCost() != null) {
            BigDecimal totalCost = detail.getUnitCost().multiply(newActualQuantity);
            detail.setTotalCost(totalCost);
        }

        // 更新明细
        boolean detailUpdateSuccess = detailService.updateById(detail);
        if (!detailUpdateSuccess) {
            throw new JeecgBootException("更新入库单明细失败");
        }

        // 更新入库单总数量和状态
        // 查询所有明细
        List<WmsInboundOrderDetail> allDetails = detailService.listByInboundOrderId(id);

        // 计算总实际入库数量
        BigDecimal totalActualQuantity = BigDecimal.ZERO;
        BigDecimal totalPlanQuantity = BigDecimal.ZERO;
        boolean allConfirmed = true;
        boolean anyConfirmed = false;

        for (WmsInboundOrderDetail item : allDetails) {
            if (item.getPlanQuantity() != null) {
                totalPlanQuantity = totalPlanQuantity.add(item.getPlanQuantity());
            }

            if (item.getActualQuantity() != null) {
                totalActualQuantity = totalActualQuantity.add(item.getActualQuantity());
                anyConfirmed = true;

                // 检查是否所有明细都已完成入库
                if (item.getActualQuantity().compareTo(item.getPlanQuantity()) < 0) {
                    allConfirmed = false;
                }
            } else {
                allConfirmed = false;
            }
        }

        // 更新入库单信息
        inboundOrder.setTotalActualQuantity(totalActualQuantity);

        // 设置实际入库时间
        inboundOrder.setActualInboundTime(new Date());

        // 更新备注
        if (StringUtils.isNotBlank(remark)) {
            String currentRemark = inboundOrder.getRemark() == null ? "" : inboundOrder.getRemark();
            if (StringUtils.isNotBlank(currentRemark)) {
                currentRemark += "\n";
            }
            currentRemark += "确认入库: " + remark;
            inboundOrder.setRemark(currentRemark);
        }

        // 设置入库单状态
        if (allConfirmed) {
            // 如果所有明细都已完成入库，则状态为已入库
            inboundOrder.setStatus(2);
        } else if (anyConfirmed) {
            // 如果有部分明细已入库，则状态为部分入库
            inboundOrder.setStatus(3);
        }

        // 设置更新人和更新时间
        LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        if (loginUser != null) {
            inboundOrder.setUpdateBy(loginUser.getUsername());
        }
        inboundOrder.setUpdateTime(new Date());

        // 更新入库单
        boolean updateSuccess = updateById(inboundOrder);
        if (!updateSuccess) {
            throw new JeecgBootException("更新入库单失败");
        }

        // 执行实际入库操作
        WmsInventory inventory = new WmsInventory();
        String materialId = detail.getMaterialId();
        WmsMaterial wmsMaterial = materialMapper.selectById(materialId);
        if (wmsMaterial != null) {
            inventory.setMaterialCode(wmsMaterial.getMaterialCode());
            inventory.setMaterialName(wmsMaterial.getMaterialName());
            inventory.setMaterialType(Integer.valueOf(wmsMaterial.getMaterialType()));
            inventory.setSpecification(wmsMaterial.getSpecification());
            inventory.setColor(wmsMaterial.getColor());
            inventory.setUnit(wmsMaterial.getUnit());
        }
        inventory.setWarehouseId(actualWarehouseId);
        inventory.setLocationId(actualLocationId);
        inventory.setUnitCost(detail.getUnitCost());
        inventory.setBatchNo(inboundOrder.getBatchNo());
        inventory.setSupplier(inboundOrder.getSupplier());

        // 执行库存入库操作
        String operator = loginUser != null ? loginUser.getUsername() : null;
        boolean inboundSuccess = inventoryService.inbound(
                inventory,
                actualQuantity,
                inboundOrder.getBusinessType(),
                inboundOrder.getBusinessNo(),
                operator,
                "入库单确认入库: " + inboundOrder.getInboundNo() + ", 明细ID: " + detailId
        );

        if (!inboundSuccess) {
            throw new JeecgBootException("执行入库操作失败");
        }

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean cancelInboundOrder(String id, String remark) {
        // 参数校验
        if (StringUtils.isBlank(id)) {
            throw new JeecgBootException("入库单ID不能为空");
        }

        // 查询入库单
        WmsInboundOrder inboundOrder = getById(id);
        if (inboundOrder == null) {
            throw new JeecgBootException("入库单不存在");
        }

        // 校验入库单状态
        if (inboundOrder.getStatus() == 2) {
            throw new JeecgBootException("已入库的入库单不能取消");
        }

        if (inboundOrder.getStatus() == 4) {
            throw new JeecgBootException("入库单已取消，不能重复取消");
        }

        // 设置入库单状态为已取消
        inboundOrder.setStatus(4);

        // 更新备注
        if (StringUtils.isNotBlank(remark)) {
            String currentRemark = inboundOrder.getRemark() == null ? "" : inboundOrder.getRemark();
            if (StringUtils.isNotBlank(currentRemark)) {
                currentRemark += "\n";
            }
            currentRemark += "取消入库: " + remark;
            inboundOrder.setRemark(currentRemark);
        }

        // 设置更新人和更新时间
        LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        if (loginUser != null) {
            inboundOrder.setUpdateBy(loginUser.getUsername());
        }
        inboundOrder.setUpdateTime(new Date());

        // 更新入库单
        return updateById(inboundOrder);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateInboundOrder(WmsInboundOrderVO inboundOrder) {
        // 参数校验
        if (inboundOrder == null || StringUtils.isBlank(inboundOrder.getId())) {
            throw new JeecgBootException("入库单ID不能为空");
        }

        // 查询原入库单
        WmsInboundOrder originalOrder = getById(inboundOrder.getId());
        if (originalOrder == null) {
            throw new JeecgBootException("入库单不存在");
        }

        // 校验入库单状态
        if (originalOrder.getStatus() != 1) {
            throw new JeecgBootException("只有待入库状态的入库单才能修改");
        }

        // 设置更新人和更新时间
        LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        if (loginUser != null) {
            inboundOrder.setUpdateBy(loginUser.getUsername());
        }
        inboundOrder.setUpdateTime(new Date());

        // 更新入库单
        boolean success = updateById(inboundOrder);
        if (!success) {
            throw new JeecgBootException("更新入库单失败");
        }

        // 检查是否需要更新明细
        List<WmsInboundOrderDetail> detailList = inboundOrder.getDetailList();
        if (detailList != null && !detailList.isEmpty()) {
            // 先删除原有明细
            detailService.deleteByInboundOrderId(inboundOrder.getId());

            // 重新保存明细
            for (WmsInboundOrderDetail detail : detailList) {
                detail.setInboundOrderId(inboundOrder.getId());
            }

            boolean detailSuccess = detailService.saveBatch(detailList);
            if (!detailSuccess) {
                throw new JeecgBootException("更新入库单明细失败");
            }

            // 重新计算总计划入库数量和总成本
            BigDecimal totalPlanQuantity = BigDecimal.ZERO;
            BigDecimal totalCost = BigDecimal.ZERO;

            for (WmsInboundOrderDetail detail : detailList) {
                if (detail.getPlanQuantity() != null) {
                    totalPlanQuantity = totalPlanQuantity.add(detail.getPlanQuantity());

                    if (detail.getUnitCost() != null) {
                        BigDecimal itemCost = detail.getUnitCost().multiply(detail.getPlanQuantity());
                        totalCost = totalCost.add(itemCost);
                    }
                }
            }

            // 更新入库单总数量和总成本
            WmsInboundOrder updateOrder = new WmsInboundOrder();
            updateOrder.setId(inboundOrder.getId());
            updateOrder.setTotalPlanQuantity(totalPlanQuantity);
            updateOrder.setTotalCost(totalCost);

            updateById(updateOrder);
        }

        return true;
    }

    public String generateInboundNo() {
        // 生成入库单号：RK + 年月日 + 6位随机数（默认格式，兼容旧逻辑）
        String prefix = "RK";
        String dateStr = String.format("%tY%<tm%<td", new Date());
        String randomNum = String.format("%06d", (int) (Math.random() * 1000000));
        return prefix + dateStr + randomNum;
    }

    /**
     * 根据业务类型生成入库单号
     */
    public String generateInboundNoByBusinessType(Integer businessType) {
        String dateStr = String.format("%tY%<tm%<td", new Date());
        String timeStr = String.format("%tH%<tM%<tS", new Date());

        String prefix;
        switch (businessType) {
            case 11:
                prefix = "CG-RK-";
                break; // 采购入库
            case 12:
                prefix = "YL-RK-";
                break; // 余料入库
            case 13:
                prefix = "DB-RK-";
                break; // 调拨入库
            case 19:
                prefix = "QT-RK-";
                break; // 其他入库
            default:
                prefix = "RK-";
                break;
        }

        return prefix + dateStr + "-" + timeStr;
    }

    @Override
    public List<WmsInboundOrderDetail> getDetailsByInboundOrderId(String inboundOrderId) {
        return detailService.listByInboundOrderId(inboundOrderId);
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean updateLocationStatus(String locationId, String status) {
        if (StringUtils.isBlank(locationId)) {
            return false;
        }

        try {
            // 更新库位状态
            Map<String, Object> params = new HashMap<>();
            params.put("id", locationId);
            params.put("status", status);

            // 调用更新库位状态的方法
            baseMapper.updateLocationStatus(params);
            return true;
        } catch (Exception e) {
            log.error("更新库位状态失败", e);
            throw new JeecgBootException("更新库位状态失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean batchConfirmInbound(String inboundOrderId, List<Map<String, Object>> details) {
        log.info("批量确认入库，入库单ID: {}, 明细数量: {}", inboundOrderId, details.size());

        // 获取入库单信息
        WmsInboundOrder inboundOrder = this.getById(inboundOrderId);
        if (inboundOrder == null) {
            log.error("未找到对应的入库单，ID: {}", inboundOrderId);
            throw new RuntimeException("未找到对应的入库单");
        }

        // 遍历明细列表
        for (Map<String, Object> detailMap : details) {
            String detailId = (String) detailMap.get("id");
            if (StringUtils.isBlank(detailId)) {
                log.error("明细ID为空");
                throw new RuntimeException("明细ID为空");
            }

            // 获取明细信息
            WmsInboundOrderDetail detail = detailService.getById(detailId);
            if (detail == null) {
                log.error("未找到对应的入库单明细，ID: {}", detailId);
                throw new RuntimeException("未找到对应的入库单明细");
            }

            // 获取实际入库仓库和库位
            String actualWarehouseId = (String) detailMap.get("actualWarehouseId");
            String actualLocationId = (String) detailMap.get("actualLocationId");

            // 获取实际入库数量
            BigDecimal actualQuantity = null;
            Object actualQtyObj = detailMap.get("actualQuantity");
            if (actualQtyObj != null) {
                if (actualQtyObj instanceof BigDecimal) {
                    actualQuantity = (BigDecimal) actualQtyObj;
                } else if (actualQtyObj instanceof Number) {
                    actualQuantity = new BigDecimal(((Number) actualQtyObj).toString());
                } else if (actualQtyObj instanceof String) {
                    try {
                        actualQuantity = new BigDecimal((String) actualQtyObj);
                    } catch (Exception e) {
                        log.error("实际入库数量格式错误: {}", actualQtyObj);
                        throw new RuntimeException("实际入库数量格式错误");
                    }
                }
            }

            if (actualQuantity == null) {
                // 如果没有指定实际入库数量，使用计划入库数量
                actualQuantity = detail.getPlanQuantity();
            }

            // 获取备注
            String remark = (String) detailMap.get("remark");

            // 更新明细信息
            detail.setActualWarehouseId(actualWarehouseId);
            detail.setActualLocationId(actualLocationId);
            detail.setActualQuantity(actualQuantity);
            detail.setRemark(remark);
            detail.setInboundStatus("1");

            // 如果实际仓库有值，查询仓库名称
            if (StringUtils.isNotBlank(actualWarehouseId)) {
                WmsWarehouse warehouse = baseMapper.getWarehouseById(actualWarehouseId);
                if (warehouse != null) {
                    detail.setActualWarehouseName(warehouse.getWarehouseName());
                }
            }

            // 如果实际库位有值，查询库位名称
            if (StringUtils.isNotBlank(actualLocationId)) {
                WmsWarehouseLocation location = baseMapper.getLocationById(actualLocationId);
                if (location != null) {
                    detail.setActualLocationName(location.getLocationName());
                }
            }

            // 检查是否需要更新库存
            Boolean updateInventory = (Boolean) detailMap.get("updateInventory");
            if (updateInventory == null) {
                updateInventory = true; // 默认为true，批量确认时更新库存
            }

            // 检查是否需要更新库位状态
            Boolean updateLocationStatus = (Boolean) detailMap.get("updateLocationStatus");
            if (updateLocationStatus != null && updateLocationStatus) {
                String locationStatus = (String) detailMap.get("locationStatus");
                if (locationStatus != null && detail.getPlanLocationId() != null) {
                    log.info("更新库位状态，库位ID: {}, 状态: {}", detail.getPlanLocationId(), locationStatus);
                    // 调用更新库位状态的方法
                    boolean locationUpdateResult = updateLocationStatus(detail.getPlanLocationId(), locationStatus);
                    if (!locationUpdateResult) {
                        log.error("批量确认入库时更新库位状态失败，库位ID: {}, 状态: {}", detail.getPlanLocationId(), locationStatus);
                        throw new RuntimeException("更新库位状态失败");
                    }
                }
            }

            // 更新明细
            boolean updateResult = detailService.updateById(detail);
            if (!updateResult) {
                log.error("更新入库单明细失败，ID: {}", detailId);
                throw new RuntimeException("更新入库单明细失败");
            }

            // 如果需要更新库存
            if (updateInventory) {
                try {
                    // 构建库存入库参数
                    Map<String, Object> inventoryParams = new HashMap<>();
                    inventoryParams.put("materialId", detail.getMaterialId());
                    inventoryParams.put("materialCode", detail.getMaterialCode());
                    inventoryParams.put("materialName", detail.getMaterialName());
                    inventoryParams.put("materialType", detail.getMaterialType());
                    inventoryParams.put("specification", detail.getSpecification());
                    inventoryParams.put("unit", detail.getUnit());
                    inventoryParams.put("warehouseId", detail.getActualWarehouseId() != null ? detail.getActualWarehouseId() : detail.getPlanWarehouseId());
                    inventoryParams.put("locationId", detail.getActualLocationId() != null ? detail.getActualLocationId() : detail.getPlanLocationId());
                    inventoryParams.put("quantity", actualQuantity);
                    inventoryParams.put("unitCost", detail.getUnitCost());
                    inventoryParams.put("batchNo", inboundOrder.getBatchNo());
                    inventoryParams.put("businessType", inboundOrder.getBusinessType());
                    inventoryParams.put("businessNo", inboundOrder.getBusinessNo());
                    inventoryParams.put("operator", detail.getUpdateBy() != null ? detail.getUpdateBy() : detail.getCreateBy());
                    inventoryParams.put("remark", "入库单批量确认入库: " + inboundOrder.getInboundNo());

                    // 调用库存服务进行入库
                    boolean inventoryResult = inventoryService.inboundWithCostAndParams(inventoryParams);
                    if (!inventoryResult) {
                        log.error("更新库存失败，入库单明细ID: {}", detail.getId());
                        throw new RuntimeException("更新库存失败");
                    }

                    log.info("库存更新成功，入库单明细ID: {}, 实际数量: {}", detail.getId(), actualQuantity);
                } catch (Exception e) {
                    log.error("更新库存时发生异常", e);
                    throw new RuntimeException("更新库存时发生异常: " + e.getMessage());
                }
            }
        }

        // 更新入库单状态
        updateInboundOrderStatus(inboundOrderId);

        return true;
    }

    /**
     * 更新入库单明细和库位状态
     *
     * @param detail          入库单明细
     * @param updateInventory 是否更新库存信息
     * @return 是否更新成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateDetailWithLocationStatus(WmsInboundOrderDetail detail, Boolean updateInventory) {
        log.info("更新入库单明细和库位状态，明细ID: {}, 是否更新库存: {}", detail.getId(), updateInventory);

        // 获取原明细
        WmsInboundOrderDetail originalDetail = detailService.getById(detail.getId());
        if (originalDetail == null) {
            log.error("未找到对应的入库单明细，ID: {}", detail.getId());
            throw new RuntimeException("未找到对应的入库单明细");
        }

        // 更新明细
        boolean updateResult = detailService.updateById(detail);
        if (!updateResult) {
            log.error("更新入库单明细失败，ID: {}", detail.getId());
            throw new RuntimeException("更新入库单明细失败");
        }

        // 如果需要更新库位状态
        if (detail.getUpdateLocationStatus() != null && detail.getUpdateLocationStatus() &&
                detail.getPlanLocationId() != null && detail.getLocationStatus() != null) {
            // 更新库位状态
            boolean locationUpdateResult = updateLocationStatus(detail.getPlanLocationId(), detail.getLocationStatus());
            if (!locationUpdateResult) {
                log.error("更新库位状态失败，库位ID: {}, 状态: {}", detail.getPlanLocationId(), detail.getLocationStatus());
                throw new RuntimeException("更新库位状态失败");
            }
        }

        // 如果需要更新库存信息
        if (updateInventory != null && updateInventory) {
            try {
                // 获取入库单信息
                WmsInboundOrderDetail byId = detailService.getById(detail.getId());
                WmsInboundOrder inboundOrder = this.getById(byId.getInboundOrderId());
                if (inboundOrder == null) {
                    log.error("未找到对应的入库单，ID: {}", detail.getInboundOrderId());
                    throw new RuntimeException("未找到对应的入库单");
                }

                // 计算实际入库数量
                BigDecimal actualQuantity = detail.getActualQuantity();
                if (actualQuantity == null || actualQuantity.compareTo(BigDecimal.ZERO) <= 0) {
                    log.warn("实际入库数量为0或负数，不更新库存");
                    return true;
                }

                // 构建库存入库参数
                Map<String, Object> inventoryParams = new HashMap<>();
                inventoryParams.put("materialId", byId.getMaterialId());
                inventoryParams.put("materialCode", byId.getMaterialCode());
                inventoryParams.put("materialName", byId.getMaterialName());
                inventoryParams.put("materialType", byId.getMaterialType());
                inventoryParams.put("specification", byId.getSpecification());
                inventoryParams.put("unit", byId.getUnit());
                inventoryParams.put("warehouseId", detail.getActualWarehouseId() != null ? detail.getActualWarehouseId() : detail.getPlanWarehouseId());
                inventoryParams.put("locationId", detail.getActualLocationId() != null ? detail.getActualLocationId() : detail.getPlanLocationId());
                inventoryParams.put("quantity", actualQuantity);
                inventoryParams.put("unitCost", detail.getUnitCost());
                inventoryParams.put("batchNo", inboundOrder.getBatchNo());
                inventoryParams.put("businessType", inboundOrder.getBusinessType());
                inventoryParams.put("businessNo", inboundOrder.getBusinessNo());
                inventoryParams.put("operator", detail.getUpdateBy() != null ? detail.getUpdateBy() : detail.getCreateBy());
                inventoryParams.put("remark", "入库单确认入库: " + inboundOrder.getInboundNo());

                // 调用库存服务进行入库
                boolean inventoryResult = inventoryService.inboundWithCostAndParams(inventoryParams);
                if (!inventoryResult) {
                    log.error("更新库存失败，入库单明细ID: {}", detail.getId());
                    throw new RuntimeException("更新库存失败");
                }

                log.info("库存更新成功，入库单明细ID: {}, 实际数量: {}", detail.getId(), actualQuantity);
            } catch (Exception e) {
                log.error("更新库存时发生异常", e);
                throw new RuntimeException("更新库存时发生异常: " + e.getMessage());
            }
        }

        // 更新入库单状态
        if (originalDetail != null && originalDetail.getInboundOrderId() != null) {
            updateInboundOrderStatus(originalDetail.getInboundOrderId());
        }

        return true;
    }

    /**
     * 保存额外库位明细，并处理仓库和库位名称
     *
     * @param detail          额外库位明细
     * @param updateInventory 是否更新库存信息
     * @return 是否保存成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveExtraLocationDetail(WmsInboundOrderDetail detail, Boolean updateInventory) {
        log.info("保存额外库位明细，是否更新库存: {}", updateInventory);

        // 设置为额外库位明细
        detail.setIsExtra(true);

        // 查询仓库和库位名称
        if (detail.getPlanWarehouseId() != null) {
            WmsWarehouse warehouse = baseMapper.getWarehouseById(detail.getPlanWarehouseId());
            if (warehouse != null) {
                detail.setPlanWarehouseName(warehouse.getWarehouseName());
            }
        }

        if (detail.getPlanLocationId() != null) {
            Map<String, Object> params = new HashMap<>();
            params.put("id", detail.getPlanLocationId());
            WmsWarehouseLocation location = baseMapper.getLocationById(detail.getPlanLocationId());
            if (location != null) {
                detail.setPlanLocationName(location.getLocationName());
            }
        }

        // 保存明细
        boolean saveResult = detailService.save(detail);
        if (!saveResult) {
            log.error("保存额外库位明细失败");
            throw new RuntimeException("保存额外库位明细失败");
        }

        // 如果需要更新库存信息
        if (updateInventory != null && updateInventory &&
                detail.getActualQuantity() != null && detail.getActualQuantity().compareTo(BigDecimal.ZERO) > 0) {

            // 查询入库单信息
            String inboundOrderId = detail.getInboundOrderId();
            WmsInboundOrder inboundOrder = this.getById(inboundOrderId);

            if (inboundOrder != null) {
                // 构建库存入库参数
                Map<String, Object> inventoryParams = new HashMap<>();
                inventoryParams.put("materialId", detail.getMaterialId());
                inventoryParams.put("materialCode", detail.getMaterialCode());
                inventoryParams.put("materialName", detail.getMaterialName());
                inventoryParams.put("materialType", detail.getMaterialType());
                inventoryParams.put("specification", detail.getSpecification());
                inventoryParams.put("unit", detail.getUnit());
                inventoryParams.put("warehouseId", detail.getPlanWarehouseId());
                inventoryParams.put("locationId", detail.getPlanLocationId());
                inventoryParams.put("quantity", detail.getActualQuantity());
                inventoryParams.put("unitCost", detail.getUnitCost());
                inventoryParams.put("batchNo", inboundOrder.getBatchNo());
                inventoryParams.put("businessType", inboundOrder.getBusinessType());
                inventoryParams.put("businessNo", inboundOrder.getBusinessNo());
                inventoryParams.put("operator", detail.getCreateBy());
                inventoryParams.put("remark", "额外库位入库: " + inboundOrder.getInboundNo());

                // 调用库存服务进行入库
                boolean inventoryResult = inventoryService.inboundWithCostAndParams(inventoryParams);
                if (!inventoryResult) {
                    log.error("更新库存失败");
                    throw new RuntimeException("更新库存失败");
                }
            }
        }

        // 更新入库单状态
        updateInboundOrderStatus(detail.getInboundOrderId());

        return true;
    }

    /**
     * 检查并更新入库单状态
     *
     * @param inboundOrderId 入库单ID
     */
    private void updateInboundOrderStatus(String inboundOrderId) {
        log.info("开始检查并更新入库单状态，入库单ID: {}", inboundOrderId);

        // 查询入库单所有明细
        List<WmsInboundOrderDetail> allDetails = detailService.listByInboundOrderId(inboundOrderId);
        log.info("查询到入库单明细数量: {}", allDetails.size());

        // 检查是否所有明细都已入库完成
        boolean allCompleted = true;
        boolean anyCompleted = false;

        BigDecimal totalPlanQuantity = BigDecimal.ZERO;
        BigDecimal totalActualQuantity = BigDecimal.ZERO;

        //获取allDetails中的planQuantity的最大值
        totalPlanQuantity = allDetails.stream()
                .map(WmsInboundOrderDetail::getPlanQuantity)
                .filter(Objects::nonNull)
                .max(BigDecimal::compareTo)
                .orElse(BigDecimal.ZERO);

        //获取allDetails中所有WmsInboundOrderDetail.status=1的 actualQuantity的总和
        totalActualQuantity = allDetails.stream()
                .filter(detail -> detail.getInboundStatus().equals("1"))
                .map(WmsInboundOrderDetail::getActualQuantity)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        //最大值>总和，则表示未全部入库
        if (totalPlanQuantity.compareTo(totalActualQuantity) > 0) {
            allCompleted = false;
        }

        if (totalActualQuantity.compareTo(BigDecimal.ZERO) > 0) {
            anyCompleted = true;
        }

        log.info("入库单状态检查结果 - 总计划数量: {}, 总实际数量: {}, 是否有入库: {}, 是否全部入库: {}",
                totalPlanQuantity, totalActualQuantity, anyCompleted, allCompleted);

        // 获取当前入库单
        WmsInboundOrder inboundOrder = getById(inboundOrderId);
        if (inboundOrder == null) {
            log.error("未找到对应的入库单，ID: {}", inboundOrderId);
            return;
        }

        // 如果所有明细都已入库完成，则更新入库单状态为已入库(2)
        if (allCompleted) {
            log.info("所有明细已入库完成，更新入库单状态为已入库(2)，入库单ID: {}", inboundOrderId);
            if (inboundOrder.getStatus() != 2) {
                inboundOrder.setStatus(2); // 已入库
                inboundOrder.setActualInboundTime(new Date()); // 设置实际入库时间
                inboundOrder.setTotalActualQuantity(totalActualQuantity); // 更新总实际入库数量
                boolean updateResult = updateById(inboundOrder);
            } else {
                log.info("入库单状态已经是已入库(2)，无需更新");
            }
        } else if (anyCompleted) {
            // 如果有部分明细已入库，则状态为部分入库(3)
            log.info("部分明细已入库，更新入库单状态为部分入库(3)，入库单ID: {}", inboundOrderId);
            if (inboundOrder.getStatus() != 3) {
                inboundOrder.setStatus(3); // 部分入库
                inboundOrder.setActualInboundTime(new Date()); // 设置实际入库时间
                inboundOrder.setTotalActualQuantity(totalActualQuantity); // 更新总实际入库数量
                boolean updateResult = updateById(inboundOrder);
                if (updateResult) {
                    log.info("成功更新入库单状态为部分入库(3)");
                } else {
                    log.error("更新入库单状态失败");
                }
            } else {
                log.info("入库单状态已经是部分入库(3)，无需更新");
            }
        } else {
            log.info("没有任何明细已入库，保持入库单当前状态不变");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean batchConfirmInboundWithHistory(String inboundOrderId, List<Map<String, Object>> details, Map<String, Object> params) {
        log.info("批量确认入库并更新库存历史，入库单ID: {}, 明细数量: {}", inboundOrderId, details.size());

        // 获取入库单信息
        WmsInboundOrder inboundOrder = this.getById(inboundOrderId);
        if (inboundOrder == null) {
            log.error("未找到对应的入库单，ID: {}", inboundOrderId);
            throw new RuntimeException("未找到对应的入库单");
        }

        // 获取操作人和操作时间
        String operator = (String) params.get("operator");
        Date operateTime = (Date) params.get("operateTime");
        Boolean updateCost = (Boolean) params.get("updateCost");

        if (operator == null) {
            // 如果没有传入操作人，尝试获取当前登录用户
            try {
                LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
                if (sysUser != null) {
                    operator = sysUser.getUsername();
                }
            } catch (Exception e) {
                log.warn("获取当前登录用户信息失败", e);
                // 使用入库单的创建人作为默认操作人
                operator = inboundOrder.getCreateBy();
            }
        }

        if (operateTime == null) {
            // 如果没有传入操作时间，使用当前时间
            operateTime = new Date();
        }

        if (updateCost == null) {
            // 默认更新成本
            updateCost = true;
        }

        // 遍历明细列表
        for (Map<String, Object> detailMap : details) {
            String detailId = (String) detailMap.get("id");
            if (StringUtils.isBlank(detailId)) {
                log.error("明细ID为空");
                throw new RuntimeException("明细ID为空");
            }

            // 获取明细信息
            WmsInboundOrderDetail detail = detailService.getById(detailId);
            if (detail == null) {
                log.error("未找到对应的入库单明细，ID: {}", detailId);
                throw new RuntimeException("未找到对应的入库单明细");
            }

            // 获取实际入库仓库和库位
            String actualWarehouseId = (String) detailMap.get("actualWarehouseId");
            String actualLocationId = (String) detailMap.get("actualLocationId");

            // 获取实际入库数量
            BigDecimal actualQuantity = null;
            Object actualQtyObj = detailMap.get("actualQuantity");
            if (actualQtyObj != null) {
                if (actualQtyObj instanceof BigDecimal) {
                    actualQuantity = (BigDecimal) actualQtyObj;
                } else if (actualQtyObj instanceof Number) {
                    actualQuantity = new BigDecimal(((Number) actualQtyObj).toString());
                } else if (actualQtyObj instanceof String) {
                    try {
                        actualQuantity = new BigDecimal((String) actualQtyObj);
                    } catch (Exception e) {
                        log.error("实际入库数量格式错误: {}", actualQtyObj);
                        throw new RuntimeException("实际入库数量格式错误");
                    }
                }
            }

            if (actualQuantity == null) {
                // 如果没有指定实际入库数量，使用计划入库数量
                actualQuantity = detail.getPlanQuantity();
            }

            // 获取备注
            String remark = (String) detailMap.get("remark");

            // 更新明细信息
            detail.setActualWarehouseId(actualWarehouseId);
            detail.setActualLocationId(actualLocationId);
            detail.setActualQuantity(actualQuantity);
            detail.setRemark(remark);
            detail.setInboundStatus("1");

            // 设置更新人和更新时间
            detail.setUpdateBy(operator);
            detail.setUpdateTime(operateTime);

            // 如果实际仓库有值，查询仓库名称
            if (StringUtils.isNotBlank(actualWarehouseId)) {
                WmsWarehouse warehouse = baseMapper.getWarehouseById(actualWarehouseId);
                if (warehouse != null) {
                    detail.setActualWarehouseName(warehouse.getWarehouseName());
                }
            }

            // 如果实际库位有值，查询库位名称
            if (StringUtils.isNotBlank(actualLocationId)) {
                WmsWarehouseLocation location = baseMapper.getLocationById(actualLocationId);
                if (location != null) {
                    detail.setActualLocationName(location.getLocationName());
                }
            }

            // 检查是否需要更新库存
            Boolean updateInventory = (Boolean) detailMap.get("updateInventory");
            if (updateInventory == null) {
                updateInventory = true; // 默认为true，批量确认时更新库存
            }

            // 检查是否需要更新库位状态
            Boolean updateLocationStatus = (Boolean) detailMap.get("updateLocationStatus");
            if (updateLocationStatus != null && updateLocationStatus) {
                String locationStatus = (String) detailMap.get("locationStatus");
                if (locationStatus != null && detail.getActualLocationId() != null) {
                    // 调用更新库位状态的方法
                    boolean locationUpdateResult = updateLocationStatus(detail.getActualLocationId(), locationStatus);
                    if (!locationUpdateResult) {
                        log.error("批量确认入库时更新库位状态失败，库位ID: {}, 状态: {}", detail.getPlanLocationId(), locationStatus);
                        throw new RuntimeException("更新库位状态失败");
                    }
                }
            }

            // 更新明细
            boolean updateResult = detailService.updateById(detail);
            if (!updateResult) {
                log.error("更新入库单明细失败，ID: {}", detailId);
                throw new RuntimeException("更新入库单明细失败");
            }

            // 如果需要更新库存
            if (updateInventory) {
                try {
                    // 构建库存入库参数
                    Map<String, Object> inventoryParams = new HashMap<>();
                    inventoryParams.put("materialId", detail.getMaterialId());
                    inventoryParams.put("materialCode", detail.getMaterialCode());
                    inventoryParams.put("materialName", detail.getMaterialName());
                    inventoryParams.put("materialType", detail.getMaterialType());
                    inventoryParams.put("specification", detail.getSpecification());
                    inventoryParams.put("unit", detail.getUnit());
                    inventoryParams.put("warehouseId", detail.getActualWarehouseId() != null ? detail.getActualWarehouseId() : detail.getPlanWarehouseId());
                    inventoryParams.put("locationId", detail.getActualLocationId() != null ? detail.getActualLocationId() : detail.getPlanLocationId());
                    inventoryParams.put("quantity", actualQuantity);

                    // 设置物料颜色 - 优先从入库明细中获取，若没有则通过物料编号查询
                    String materialColor = detail.getColor();
                    if (StringUtils.isBlank(materialColor) && StringUtils.isNotBlank(detail.getMaterialCode())) {
                        try {
                            WmsMaterial material = materialMapper.selectOne(new LambdaQueryWrapper<WmsMaterial>()
                                    .eq(WmsMaterial::getMaterialCode, detail.getMaterialCode())
                                    .eq(WmsMaterial::getStatus, "0"));
                            if (material != null) {
                                materialColor = material.getColor();
                                log.debug("从物料基础信息中获取颜色: 物料编码[{}], 颜色[{}]", detail.getMaterialCode(), materialColor);
                            }
                        } catch (Exception e) {
                            log.warn("通过物料编码[{}]查询颜色信息失败: {}", detail.getMaterialCode(), e.getMessage());
                        }
                    }
                    inventoryParams.put("materialColor", materialColor);

                    // 处理成本信息
                    BigDecimal unitCost = null;
                    // 首先从明细参数中获取单位成本
                    Object unitCostObj = detailMap.get("unitCost");
                    if (unitCostObj != null) {
                        if (unitCostObj instanceof BigDecimal) {
                            unitCost = (BigDecimal) unitCostObj;
                        } else if (unitCostObj instanceof Number) {
                            unitCost = new BigDecimal(((Number) unitCostObj).toString());
                        } else if (unitCostObj instanceof String && !((String) unitCostObj).trim().isEmpty()) {
                            try {
                                unitCost = new BigDecimal((String) unitCostObj);
                            } catch (Exception e) {
                                log.warn("单位成本格式错误: {}, 将使用明细中的单位成本", unitCostObj);
                            }
                        }
                    }

                    // 如果明细参数中没有单位成本，尝试从明细对象中获取
                    if (unitCost == null || unitCost.compareTo(BigDecimal.ZERO) <= 0) {
                        unitCost = detail.getUnitCost();
                    }

                    // 根据updateCost标志决定是否设置单位成本
                    if (updateCost && unitCost != null && unitCost.compareTo(BigDecimal.ZERO) > 0) {
                        inventoryParams.put("unitCost", unitCost);
                        log.info("入库时更新成本信息，单位成本: {}", unitCost);
                    } else {
                        // 不更新成本，或者没有有效的成本信息
                        log.info("入库时不更新成本信息或没有有效的成本信息，updateCost: {}, unitCost: {}", updateCost, unitCost);
                        inventoryParams.put("updateCost", false);
                    }

                    inventoryParams.put("batchNo", inboundOrder.getBatchNo());
                    inventoryParams.put("businessType", inboundOrder.getBusinessType());
                    inventoryParams.put("businessNo", inboundOrder.getBusinessNo());
                    inventoryParams.put("operator", operator);
                    inventoryParams.put("operateTime", operateTime);
                    inventoryParams.put("remark", "入库单批量确认入库: " + inboundOrder.getInboundNo());

                    // 调用库存服务进行入库
                    boolean inventoryResult = inventoryService.inboundWithCostAndParams(inventoryParams);
                    if (!inventoryResult) {
                        log.error("更新库存失败，入库单明细ID: {}", detail.getId());
                        throw new RuntimeException("更新库存失败");
                    }

                    log.info("库存更新成功，入库单明细ID: {}, 实际数量: {}", detail.getId(), actualQuantity);
                } catch (Exception e) {
                    log.error("更新库存时发生异常", e);
                    throw new RuntimeException("更新库存时发生异常: " + e.getMessage());
                }
            }
        }

        // 更新入库单状态
        updateInboundOrderStatus(inboundOrderId);

        return true;
    }

    /**
     * 为调拨入库单创建对应的调拨出库记录
     */
    private void createTransferOutboundRecord(WmsInboundOrderVO inboundOrder) {
        try {
            // 创建调拨出库单主表
            WmsOutbound outbound = new WmsOutbound();

            // 生成出库单号
            String outboundNo = generateTransferOutboundNo();
            outbound.setOutboundNo(outboundNo);

            // 设置出库类型为调拨出库（3）
            outbound.setOutboundType("3");

            // 设置状态为待审核1
            outbound.setStatus("1");

            // 设置出库日期为当前日期
            outbound.setOutboundDate(new Date());

            //设置关联入库单ID
            outbound.setRequisitionId(inboundOrder.getId());

            // 设置关联的入库单号
            outbound.setRequisitionNo(inboundOrder.getInboundNo());

            // 设置备注
            outbound.setRemark("根据调拨入库单 " + inboundOrder.getInboundNo() + " 自动生成的调拨出库记录");

            // 获取当前操作人
            LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
            if (loginUser != null) {
                outbound.setCreateBy(loginUser.getUsername());
                outbound.setCreateTime(new Date());
            }

            // 保存出库单主表
            boolean saveResult = wmsOutboundService.save(outbound);
            if (!saveResult) {
                throw new RuntimeException("保存调拨出库单主表失败");
            }

            // 创建并保存出库单明细
            List<WmsInboundOrderMaterialVO> materialList = inboundOrder.getMaterialList();
            if (materialList != null && !materialList.isEmpty()) {
                List<WmsOutboundDetail> outboundDetailList = new ArrayList<>();

                for (WmsInboundOrderMaterialVO material : materialList) {
                    // 只有设置了源仓库信息的物料才创建出库明细
                    if (material.getSourceWarehouseId() != null && !material.getSourceWarehouseId().isEmpty()) {
                        WmsOutboundDetail outboundDetail = new WmsOutboundDetail();

                        outboundDetail.setOutboundId(outbound.getId());
                        outboundDetail.setMaterialCode(material.getMaterialCode());
                        outboundDetail.setMaterialName(material.getMaterialName());
                        outboundDetail.setMaterialType(String.valueOf(material.getMaterialType()));
                        outboundDetail.setSpecification(material.getSpecification());
                        outboundDetail.setUnit(material.getUnit());
                        outboundDetail.setQuantity(material.getPlanQuantity());

                        // 设置源仓库和库位信息（出库的仓库和库位）
                        outboundDetail.setWarehouseId(material.getSourceWarehouseId());
                        outboundDetail.setWarehouseName(material.getSourceWarehouseName());
                        outboundDetail.setLocationId(material.getSourceLocationId());
                        outboundDetail.setLocationName(material.getSourceLocationName());

                        // 设置目标仓库和库位信息（入库的仓库和库位）
                        outboundDetail.setTargetWarehouseId(material.getPlanWarehouseId());
                        outboundDetail.setTargetWarehouseName(material.getPlanWarehouseName());
                        outboundDetail.setTargetLocationId(material.getPlanLocationId());
                        outboundDetail.setTargetLocationName(material.getPlanLocationName());

                        outboundDetail.setBatchNo(inboundOrder.getBatchNo());
                        outboundDetail.setRemark("调拨入库单自动生成");

                        if (loginUser != null) {
                            outboundDetail.setCreateBy(loginUser.getUsername());
                            outboundDetail.setCreateTime(new Date());
                        }

                        outboundDetailList.add(outboundDetail);
                    }
                }

                // 批量保存出库明细
                if (!outboundDetailList.isEmpty()) {
                    boolean detailSaveResult = wmsOutboundDetailService.saveBatch(outboundDetailList);
                    if (!detailSaveResult) {
                        throw new RuntimeException("保存调拨出库单明细失败");
                    }
                    log.info("成功保存 {} 条调拨出库明细记录", outboundDetailList.size());
                }
            }

            log.info("成功为调拨入库单 {} 创建调拨出库记录 {}", inboundOrder.getInboundNo(), outboundNo);

        } catch (Exception e) {
            log.error("创建调拨出库记录失败", e);
            throw new RuntimeException("创建调拨出库记录失败: " + e.getMessage());
        }
    }

    /**
     * 生成调拨出库单号
     */
    private String generateTransferOutboundNo() {
        String dateStr = String.format("%tY%<tm%<td", new Date());
        String timeStr = String.format("%tH%<tM%<tS", new Date());
        return "DB-CK-" + dateStr + "-" + timeStr;
    }


    /**
     * 从Map中获取字符串值
     */
    private String getString(Map<String, Object> map, String key) {
        Object value = map.get(key);
        return value != null ? value.toString() : null;
    }

    /**
     * 从Map中获取整数值
     */
    private Integer getInteger(Map<String, Object> map, String key) {
        Object value = map.get(key);
        if (value == null) {
            return null;
        }
        if (value instanceof Integer) {
            return (Integer) value;
        }
        if (value instanceof String) {
            try {
                return Integer.parseInt((String) value);
            } catch (NumberFormatException e) {
                return null;
            }
        }
        return null;
    }

    @Override
    public void triggerOutboundReallocationAfterInbound(List<Map<String, Object>> inboundDetails) {
        try {
            if (inboundDetails == null || inboundDetails.isEmpty()) {
                return;
            }

            // 提取入库物料编码列表
            Set<String> materialCodes = new HashSet<>();
            for (Map<String, Object> detail : inboundDetails) {
                String materialCode = getString(detail, "materialCode");
                if (oConvertUtils.isNotEmpty(materialCode)) {
                    materialCodes.add(materialCode);
                }
            }

            if (materialCodes.isEmpty()) {
                return;
            }

            log.info("入库成功后触发出库明细重新分配，涉及物料: {}", materialCodes);

            // 查询涉及这些物料的出库明细（状态为部分分配或未分配的）
            QueryWrapper<WmsOutboundDetail> queryWrapper = new QueryWrapper<>();
            queryWrapper.in("material_code", materialCodes);
            queryWrapper.in("allocation_status", Arrays.asList("2", "3")); // 2-部分分配，3-未分配
            queryWrapper.gt("remaining_quantity", 0); // 剩余数量大于0
            queryWrapper.orderByAsc("create_time"); // 按创建时间排序，优先分配较早的出库明细

            List<WmsOutboundDetail> outboundDetails = wmsOutboundDetailService.list(queryWrapper);
            if (outboundDetails.isEmpty()) {
                log.info("没有找到需要重新分配的出库明细");
                return;
            }

            log.info("找到 {} 条需要重新分配的出库明细", outboundDetails.size());

            // 串行分配出库明细，确保每次分配后库存数据是最新的
            for (WmsOutboundDetail outboundDetail : outboundDetails) {
                try {
                    // 重新获取最新的出库明细数据，确保数据一致性
                    WmsOutboundDetail latestDetail = wmsOutboundDetailService.getById(outboundDetail.getId());
                    if (latestDetail == null || latestDetail.getRemainingQuantity().compareTo(BigDecimal.ZERO) <= 0) {
                        log.info("出库明细已完全分配或不存在，跳过: ID={}", outboundDetail.getId());
                        continue;
                    }

                    allocateOutboundDetail(latestDetail);

                    // 分配完成后，强制刷新库存缓存，确保下次查询获取最新数据
                    log.info("出库明细分配完成: ID={}, 物料编码={}", latestDetail.getId(), latestDetail.getMaterialCode());

                } catch (Exception e) {
                    log.error("分配出库明细失败: 出库明细ID={}, 物料编码={}",
                            outboundDetail.getId(), outboundDetail.getMaterialCode(), e);
                    // 继续处理下一个，不因单个失败而中断整个流程
                }
            }

        } catch (Exception e) {
            log.error("入库成功后触发出库明细重新分配失败", e);
            throw new RuntimeException("出库明细重新分配失败: " + e.getMessage());
        }
    }

    /**
     * 分配出库明细
     */
    private void allocateOutboundDetail(WmsOutboundDetail outboundDetail) {
        try {
            log.info("开始分配出库明细: 物料={}, 剩余数量={}",
                    outboundDetail.getMaterialCode(), outboundDetail.getRemainingQuantity());

            BigDecimal remainingToAllocate = outboundDetail.getRemainingQuantity();
            BigDecimal totalAllocated = outboundDetail.getAllocatedQuantity() != null ?
                    outboundDetail.getAllocatedQuantity() : BigDecimal.ZERO;

            // 循环分配，每次都重新查询最新的库存数据
            while (remainingToAllocate.compareTo(BigDecimal.ZERO) > 0) {
                // 每次循环都重新查询该物料的可用库存，确保获取最新数据
                QueryWrapper<WmsInventory> inventoryQuery = new QueryWrapper<>();
                inventoryQuery.eq("material_code", outboundDetail.getMaterialCode());
                inventoryQuery.gt("available_quantity", 0); // 可用数量大于0
                inventoryQuery.orderByAsc("create_time"); // 先进先出
                inventoryQuery.last("LIMIT 1"); // 每次只取一条记录进行分配

                List<WmsInventory> inventoryList = wmsInventoryService.list(inventoryQuery);
                if (inventoryList.isEmpty()) {
                    log.info("物料 {} 无可用库存，分配结束", outboundDetail.getMaterialCode());
                    break;
                }

                WmsInventory inventory = inventoryList.get(0);

                // 重新获取最新的库存数据，确保数据一致性
                WmsInventory latestInventory = wmsInventoryService.getById(inventory.getId());
                if (latestInventory == null || latestInventory.getAvailableQuantity().compareTo(BigDecimal.ZERO) <= 0) {
                    log.info("库存记录不存在或无可用数量，跳过: 库存ID={}", inventory.getId());
                    continue;
                }
                //可用的库存数量
                BigDecimal availableQuantity = latestInventory.getAvailableQuantity();

                // 计算本次分配数量
                BigDecimal allocateQuantity = remainingToAllocate.min(availableQuantity);

                // 更新库存的预出库数量和可用数量
                BigDecimal newPreOutboundQuantity = latestInventory.getPreOutboundQuantity().add(allocateQuantity);
                BigDecimal newAvailableQuantity = availableQuantity.subtract(allocateQuantity);

                WmsInventory updateInventory = new WmsInventory();
                updateInventory.setId(latestInventory.getId());
                updateInventory.setPreOutboundQuantity(newPreOutboundQuantity);
                updateInventory.setAvailableQuantity(newAvailableQuantity);
                updateInventory.setUpdateTime(new Date());

                boolean inventoryUpdated = wmsInventoryService.updateById(updateInventory);
                if (!inventoryUpdated) {
                    log.error("更新库存失败: 库存ID={}", latestInventory.getId());
                    break; // 更新失败则停止分配
                }

                // 创建或更新分配方案记录
                createAllocationPlan(outboundDetail, latestInventory, allocateQuantity);

                // 更新已分配数量和剩余数量
                totalAllocated = totalAllocated.add(allocateQuantity);
                remainingToAllocate = remainingToAllocate.subtract(allocateQuantity);

                log.info("分配成功: 物料={}, 库存ID={}, 分配数量={}, 剩余待分配={}",
                        outboundDetail.getMaterialCode(), latestInventory.getId(), allocateQuantity, remainingToAllocate);
            }

            // 更新出库明细的分配状态
            WmsOutboundDetail updateDetail = new WmsOutboundDetail();
            updateDetail.setId(outboundDetail.getId());
            updateDetail.setAllocatedQuantity(totalAllocated);
            updateDetail.setRemainingQuantity(remainingToAllocate);

            // 确定分配状态
            String allocationStatus;
            if (remainingToAllocate.compareTo(BigDecimal.ZERO) <= 0) {
                allocationStatus = "1"; // 完全分配
            } else if (totalAllocated.compareTo(BigDecimal.ZERO) > 0) {
                allocationStatus = "2"; // 部分分配
            } else {
                allocationStatus = "3"; // 未分配
            }
            updateDetail.setAllocationStatus(allocationStatus);
            updateDetail.setUpdateTime(new Date());

            boolean detailUpdated = wmsOutboundDetailService.updateById(updateDetail);
            if (!detailUpdated) {
                log.error("更新出库明细失败: 明细ID={}", outboundDetail.getId());
                return;
            }

            log.info("出库明细分配完成: 物料={}, 总分配数量={}, 剩余数量={}, 状态={}",
                    outboundDetail.getMaterialCode(), totalAllocated, remainingToAllocate, allocationStatus);

        } catch (Exception e) {
            log.error("分配出库明细失败: 明细ID={}", outboundDetail.getId(), e);
            throw new RuntimeException("分配出库明细失败: " + e.getMessage());
        }
    }

    @Autowired
    private IWmsOutboundAllocationPlanService allocationPlanService;

    /**
     * 创建分配方案记录
     */
    private void createAllocationPlan(WmsOutboundDetail outboundDetail, WmsInventory inventory, BigDecimal allocateQuantity) {
        try {
            WmsOutboundAllocationPlan allocationPlan = new WmsOutboundAllocationPlan();
            allocationPlan.setOutboundId(outboundDetail.getOutboundId());
            allocationPlan.setInventoryId(inventory.getId()); // 设置库存ID
            allocationPlan.setMaterialCode(outboundDetail.getMaterialCode());
            allocationPlan.setMaterialName(outboundDetail.getMaterialName());
            allocationPlan.setMaterialType(Integer.valueOf(outboundDetail.getMaterialType()));
            allocationPlan.setSpecification(outboundDetail.getSpecification());
            allocationPlan.setColor(outboundDetail.getColor());
            allocationPlan.setUnit(outboundDetail.getUnit());

            allocationPlan.setWarehouseId(inventory.getWarehouseId());
            allocationPlan.setWarehouseName(inventory.getWarehouseName());
            allocationPlan.setLocationId(inventory.getLocationId());
            allocationPlan.setLocationName(inventory.getLocationName());
            allocationPlan.setBatchNo(inventory.getBatchNo());

            allocationPlan.setRequiredQuantity(outboundDetail.getQuantity());
            allocationPlan.setAllocationQuantity(allocateQuantity);
            allocationPlan.setAvailableQuantity(inventory.getAvailableQuantity().add(allocateQuantity)); // 分配前的可用数量
            allocationPlan.setAllocationStatus(1); // 已分配
            allocationPlan.setPriority(1);

            allocationPlan.setCreateBy("system");
            allocationPlan.setCreateTime(new Date());
            allocationPlan.setRemark("入库后自动分配");

            allocationPlanService.save(allocationPlan);

            log.debug("创建分配方案记录成功: 出库明细ID={}, 库存ID={}, 分配数量={}",
                    outboundDetail.getId(), inventory.getId(), allocateQuantity);

        } catch (Exception e) {
            log.error("创建分配方案记录失败: 出库明细ID={}, 库存ID={}",
                    outboundDetail.getId(), inventory.getId(), e);
        }
    }

    @Override
    public IPage<WmsInboundOrderVO> queryInboundOrderForMobile(Page<WmsInboundOrderVO> page, Map<String, Object> query) {
        log.info("移动端入库单查询，查询条件: {}", query);
        return baseMapper.queryInboundOrderForMobile(page, query);
    }

    @Override
    public IPage<WmsInboundOrderVO> getUserOperationRecords(Page<WmsInboundOrderVO> page, WmsInboundOrder queryParam,
                                                            String planInboundStartTime, String planInboundEndTime,
                                                            String actualInboundStartTime, String actualInboundEndTime,
                                                            String warehouseName, String locationName,
                                                            String materialCode, String materialName,
                                                            List<String> statusList, List<String> businessTypeList) {
        try {
            // 获取当前用户信息
            LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
            if (loginUser == null) {
                throw new RuntimeException("用户未登录");
            }

            String userId = loginUser.getId();
            log.info("查询用户入库操作记录，用户ID: {}, 筛选条件: {}", userId, queryParam);

            // 构建查询条件
            LambdaQueryWrapper<WmsInboundOrder> queryWrapper = new LambdaQueryWrapper<>();

            // 用户权限过滤
            queryWrapper.and(wrapper ->
                    wrapper.like(WmsInboundOrder::getOperatorIds, userId)
            );

            // 添加筛选条件
            if (queryParam != null) {
                if (StringUtils.isNotBlank(queryParam.getInboundNo())) {
                    queryWrapper.like(WmsInboundOrder::getInboundNo, queryParam.getInboundNo());
                }
                if (statusList != null) {
                    queryWrapper.in(WmsInboundOrder::getStatus, statusList);
                }
                if (businessTypeList != null) {
                    queryWrapper.in(WmsInboundOrder::getBusinessType, businessTypeList);
                }
            }

            // 时间范围筛选
            if (StringUtils.isNotBlank(planInboundStartTime)) {
                queryWrapper.ge(WmsInboundOrder::getPlanInboundTime, planInboundStartTime);
            }
            if (StringUtils.isNotBlank(planInboundEndTime)) {
                queryWrapper.le(WmsInboundOrder::getPlanInboundTime, planInboundEndTime);
            }
            if (StringUtils.isNotBlank(actualInboundStartTime)) {
                queryWrapper.ge(WmsInboundOrder::getActualInboundTime, actualInboundStartTime);
            }
            if (StringUtils.isNotBlank(actualInboundEndTime)) {
                queryWrapper.le(WmsInboundOrder::getActualInboundTime, actualInboundEndTime);
            }

            queryWrapper.orderByDesc(WmsInboundOrder::getUpdateTime);

            Page<WmsInboundOrder> entityPage = new Page<>(page.getCurrent(), page.getSize());
            IPage<WmsInboundOrder> inboundPage = this.page(entityPage, queryWrapper);

            // 转换为VO对象
            List<WmsInboundOrderVO> voList = new ArrayList<>();
            for (WmsInboundOrder inboundOrder : inboundPage.getRecords()) {
                WmsInboundOrderVO vo = this.getInboundOrderByIdAndUpdateBy(inboundOrder.getId(), loginUser.getUsername());
                if (vo != null) {
                    // 如果有仓库、库位、物料筛选条件，需要进一步过滤
                    if (shouldIncludeRecord(vo, warehouseName, locationName, materialCode, materialName)) {
                        voList.add(vo);
                    }
                }
            }

            // 构建返回结果
            Page<WmsInboundOrderVO> resultPage = new Page<>(page.getCurrent(), page.getSize(), inboundPage.getTotal());
            resultPage.setRecords(voList);

            log.info("查询用户入库操作记录完成，返回 {} 条记录", voList.size());
            return resultPage;

        } catch (Exception e) {
            log.error("查询用户入库操作记录失败", e);
            throw new RuntimeException("查询用户入库操作记录失败: " + e.getMessage());
        }
    }

    /**
     * 检查记录是否符合筛选条件
     */
    private boolean shouldIncludeRecord(WmsInboundOrderVO vo, String warehouseName, String locationName,
                                        String materialCode, String materialName) {
        // 如果没有明细相关的筛选条件，直接返回true
        if (StringUtils.isBlank(warehouseName) && StringUtils.isBlank(locationName) &&
                StringUtils.isBlank(materialCode) && StringUtils.isBlank(materialName)) {
            return true;
        }

        // 检查仓库名称 - 通过明细中的仓库信息检查
        boolean warehouseMatched = StringUtils.isBlank(warehouseName);

        // 检查明细中的筛选条件
        if (vo.getDetailList() != null && !vo.getDetailList().isEmpty()) {
            for (WmsInboundOrderDetail detail : vo.getDetailList()) {
                // 检查仓库名称
                if (StringUtils.isNotBlank(warehouseName)) {
                    if (StringUtils.isNotBlank(detail.getPlanWarehouseName()) &&
                            detail.getPlanWarehouseName().contains(warehouseName)) {
                        warehouseMatched = true;
                    }
                    if (StringUtils.isNotBlank(detail.getActualWarehouseName()) &&
                            detail.getActualWarehouseName().contains(warehouseName)) {
                        warehouseMatched = true;
                    }
                }

                // 检查库位名称
                if (StringUtils.isNotBlank(locationName)) {
                    if ((StringUtils.isNotBlank(detail.getPlanLocationName()) &&
                            detail.getPlanLocationName().contains(locationName)) ||
                            (StringUtils.isNotBlank(detail.getActualLocationName()) &&
                                    detail.getActualLocationName().contains(locationName))) {
                        return true;
                    }
                }

                // 检查物料编码
                if (StringUtils.isNotBlank(materialCode)) {
                    if (StringUtils.isNotBlank(detail.getMaterialCode()) &&
                            detail.getMaterialCode().contains(materialCode)) {
                        return true;
                    }
                }

                // 检查物料名称
                if (StringUtils.isNotBlank(materialName)) {
                    if (StringUtils.isNotBlank(detail.getMaterialName()) &&
                            detail.getMaterialName().contains(materialName)) {
                        return true;
                    }
                }
            }

            // 如果有明细筛选条件但没有匹配的明细，返回false
            if (StringUtils.isNotBlank(locationName) || StringUtils.isNotBlank(materialCode) ||
                    StringUtils.isNotBlank(materialName)) {
                return false;
            }
        }

        // 返回仓库匹配结果
        return warehouseMatched;
    }

    @Override
    public Long getMaterialInboundOrderCount() {
        try {
            LambdaQueryWrapper<WmsInboundOrder> queryWrapper = new LambdaQueryWrapper<>();
            // 查询物料入库单 排除已取消出库单
            queryWrapper.ne(WmsInboundOrder::getStatus, 4);
            return this.count(queryWrapper);
        } catch (Exception e) {
            log.error("获取物料入库单总数失败", e);
            return 0L;
        }
    }

    @Override
    public Long getMaterialOutboundOrderCount() {
        try {
            LambdaQueryWrapper<WmsInboundOrder> queryWrapper = new LambdaQueryWrapper<>();
            // 查询物料出库单（业务类型为21-生产领料出库、22-仓库调拨出库等出库类型）
            return wmsOutboundService.count(new LambdaQueryWrapper<WmsOutbound>()
                    .notIn(WmsOutbound::getStatus, 0, 1, 4));
        } catch (Exception e) {
            log.error("获取物料出库单总数失败", e);
            return 0L;
        }
    }

    @Autowired
    private IProductSalesOrderService productSalesOrderService;

    /**
     * 生产领料出库单执行完成自动生成余料入库单
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String autoCreateSurplusInboundOrder(String orderId, String outboundOrderId) {
        try {
            log.info("开始自动创建订单[{}]的生产余料入库单，关联出库单[{}]", orderId, outboundOrderId);

            // 参数校验
            if (StringUtils.isBlank(orderId)) {
                throw new JeecgBootException("订单ID不能为空");
            }

            // 1. 获取有效余料信息（已过滤余料下限）
            List<SurplusMaterialVO> validSurplusMaterials = surplusMaterialService.getValidSurplusMaterialsByOrderId(orderId);
            if (validSurplusMaterials.isEmpty()) {
                log.info("订单[{}]无有效余料信息，跳过余料入库单生成", orderId);
                return null;
            }

            log.info("订单[{}]找到{}个有效余料", orderId, validSurplusMaterials.size());

            // 2. 为余料自动分配库位
            List<WmsInboundOrderMaterialVO> materialVOList = autoLocationAllocationService.allocateLocationsForSurplus(validSurplusMaterials);
            if (materialVOList.isEmpty()) {
                log.warn("订单[{}]余料库位分配失败，无法创建余料入库单", orderId);
                throw new JeecgBootException("余料库位分配失败，无法创建余料入库单");
            }

            log.info("订单[{}]成功分配库位的余料数量: {}", orderId, materialVOList.size());

            // 3. 创建余料入库单VO
            WmsInboundOrderVO inboundOrderVO = new WmsInboundOrderVO();

            // 设置基本信息
            inboundOrderVO.setBusinessType(12); // 余料入库
            String[] orderIdArray = orderId.split(",");
            List<Object> orderNoList = productSalesOrderService.listObjs(new LambdaQueryWrapper<ProductSalesOrder>()
                    .in(ProductSalesOrder::getId, orderIdArray)
                    .select(ProductSalesOrder::getOrderNo));
            //拼接orderNoList，逗号间隔
            String orderNo = orderNoList.stream()
                    .map(Object::toString)
                    .collect(Collectors.joining(","));
            inboundOrderVO.setBusinessNo(orderNo);
            inboundOrderVO.setIsSurplus(true);
            inboundOrderVO.setRemark("订单[" + orderId + "]生产完成后自动生成的余料入库单");

            // 关联生产订单信息
            inboundOrderVO.setProductionOrderId(orderId);

            // 设置物料列表
            inboundOrderVO.setMaterialList(materialVOList);

            // 4. 调用创建余料入库单方法
            String inboundNo = createSurplusInboundOrder(inboundOrderVO);

            log.info("订单[{}]自动创建余料入库单成功，入库单号: {}", orderId, inboundNo);
            return inboundNo;

        } catch (Exception e) {
            log.error("自动创建订单[{}]余料入库单失败", orderId, e);
            throw new JeecgBootException("自动创建余料入库单失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String autoGenerateInboundOrderFromArrival(String purchaseOrderId, String arrivalDate,
                                                      List<Map<String, Object>> arrivalDetails, String username) {
        try {
            log.info("开始根据采购到货信息自动生成入库单，采购单ID: {}", purchaseOrderId);

            // 1. 获取采购单基本信息
            WmsPurchaseOrder purchaseOrder = wmsPurchaseOrderService.getById(purchaseOrderId);
            if (purchaseOrder == null) {
                log.warn("采购单不存在，ID: {}", purchaseOrderId);
                return null;
            }

            // 2. 过滤出合格数量大于0的物料
            List<WmsInboundOrderMaterialVO> qualifiedMaterials = new ArrayList<>();

            for (Map<String, Object> detail : arrivalDetails) {
                String materialId = (String) detail.get("materialId");
                Object qualifiedQtyObj = detail.get("qualifiedQuantity");

                if (materialId == null || qualifiedQtyObj == null) {
                    continue;
                }

                BigDecimal qualifiedQuantity;
                if (qualifiedQtyObj instanceof BigDecimal) {
                    qualifiedQuantity = (BigDecimal) qualifiedQtyObj;
                } else if (qualifiedQtyObj instanceof Number) {
                    qualifiedQuantity = new BigDecimal(qualifiedQtyObj.toString());
                } else {
                    try {
                        qualifiedQuantity = new BigDecimal(qualifiedQtyObj.toString());
                    } catch (NumberFormatException e) {
                        log.warn("合格数量格式错误，跳过物料: {}, 数量: {}", materialId, qualifiedQtyObj);
                        continue;
                    }
                }

                // 只处理合格数量大于0的物料
                if (qualifiedQuantity.compareTo(BigDecimal.ZERO) > 0) {
                    // 获取物料详细信息
                    WmsMaterial material = wmsMaterialService.getById(materialId);
                    if (material != null) {
                        WmsInboundOrderMaterialVO materialVO = new WmsInboundOrderMaterialVO();
                        materialVO.setMaterialId(materialId);
                        materialVO.setMaterialCode(material.getMaterialCode());
                        materialVO.setMaterialName(material.getMaterialName());
                        materialVO.setMaterialType(Integer.valueOf(material.getMaterialType()));
                        materialVO.setSpecification(material.getSpecification());
                        materialVO.setUnit(material.getUnit());
                        materialVO.setPlanQuantity(qualifiedQuantity);
                        materialVO.setColor(material.getColor());

                        // 设置单位成本（从采购单明细获取）
                        Object unitCostObj = detail.get("unitPrice");
                        if (unitCostObj != null) {
                            try {
                                BigDecimal unitCost = new BigDecimal(unitCostObj.toString());
                                materialVO.setUnitCost(unitCost);
                            } catch (NumberFormatException e) {
                                log.warn("单价格式错误，使用默认值0，物料: {}, 单价: {}", materialId, unitCostObj);
                                materialVO.setUnitCost(BigDecimal.ZERO);
                            }
                        } else {
                            materialVO.setUnitCost(BigDecimal.ZERO);
                        }

                        // 根据物料类型推荐仓库和库位
                        recommendWarehouseAndLocation(materialVO);

                        qualifiedMaterials.add(materialVO);
                    }
                }
            }

            // 3. 如果没有合格物料，不生成入库单
            if (qualifiedMaterials.isEmpty()) {
                log.info("采购单[{}]没有合格物料，不生成入库单", purchaseOrderId);
                return null;
            }

            // 4. 构建入库单信息
            WmsInboundOrderVO inboundOrderVO = new WmsInboundOrderVO();
            inboundOrderVO.setBusinessType(11); // 采购入库
            inboundOrderVO.setPurchaseOrderNo(purchaseOrder.getPurchaseNo());
            inboundOrderVO.setBusinessNo(purchaseOrder.getPurchaseNo());
            //字符串arrivalDate转日期
            Date date = DateUtils.parseDate(arrivalDate, "yyyy-MM-dd");
            inboundOrderVO.setPlanInboundTime(date);
            inboundOrderVO.setRemark("采购单[" + purchaseOrder.getPurchaseNo() + "]到货后自动生成的入库单");
            inboundOrderVO.setMaterialList(qualifiedMaterials);

            // 5. 创建入库单
            String inboundOrderId = createInboundOrder(inboundOrderVO);

            log.info("采购单[{}]自动生成入库单成功，入库单ID: {}", purchaseOrderId, inboundOrderId);
            return inboundOrderId;

        } catch (Exception e) {
            log.error("根据采购到货信息自动生成入库单失败，采购单ID: {}", purchaseOrderId, e);
            throw new JeecgBootException("自动生成采购入库单失败: " + e.getMessage());
        }
    }

    /**
     * 根据物料类型推荐仓库和库位
     *
     * @param materialVO 物料信息
     */
    private void recommendWarehouseAndLocation(WmsInboundOrderMaterialVO materialVO) {
        try {
            Integer materialType = materialVO.getMaterialType();
            if (materialType == null) {
                return;
            }

            // 根据物料类型推荐仓库
            String warehouseName;
            switch (materialType) {
                case 1: // 型材
                    warehouseName = "型材仓库";
                    break;
                case 2: // 配件
                    warehouseName = "配件仓库";
                    break;
                case 3: // 辅件
                    warehouseName = "辅件仓库";
                    break;
                case 5: // 余料
                    warehouseName = "余料仓库";
                    break;
                case 6: // 半料
                    warehouseName = "半料仓库";
                    break;
                default: // 其他
                    warehouseName = "综合仓库";
                    break;
            }

            // 查找对应的仓库
            WmsWarehouse warehouse = wmsWarehouseService.getOne(
                    new LambdaQueryWrapper<WmsWarehouse>()
                            .eq(WmsWarehouse::getWarehouseName, warehouseName)
                            .eq(WmsWarehouse::getStatus, "1")
                            .last("LIMIT 1")
            );

            if (warehouse != null) {
                materialVO.setPlanWarehouseId(warehouse.getId());
                materialVO.setPlanWarehouseName(warehouse.getWarehouseName());

                // 查找该仓库下的可用库位
                WmsWarehouseLocation location = wmsWarehouseLocationService.getOne(
                        new LambdaQueryWrapper<WmsWarehouseLocation>()
                                .eq(WmsWarehouseLocation::getWarehouseId, warehouse.getId())
                                .eq(WmsWarehouseLocation::getStatus, "1")
                                .orderByAsc(WmsWarehouseLocation::getLocationCode)
                                .last("LIMIT 1")
                );

                if (location != null) {
                    materialVO.setPlanLocationId(location.getId());
                    materialVO.setPlanLocationName(location.getLocationName());
                }
            }

        } catch (Exception e) {
            log.warn("推荐仓库库位失败，物料: {}", materialVO.getMaterialCode(), e);
            // 推荐失败不影响主流程，继续执行
        }
    }

    @Override
    public List<Map<String, Object>> parseRemainingMaterialExcel(MultipartFile file) {
        List<Map<String, Object>> result = new ArrayList<>();

        try {
            Workbook workbook = null;
            String fileName = file.getOriginalFilename();

            // 根据文件扩展名创建对应的工作簿
            if (fileName.endsWith(".xlsx")) {
                workbook = new XSSFWorkbook(file.getInputStream());
            } else if (fileName.endsWith(".xls")) {
                workbook = new HSSFWorkbook(file.getInputStream());
            } else {
                throw new JeecgBootException("不支持的文件格式，请上传.xlsx或.xls文件");
            }

            // 获取第一个工作表
            Sheet sheet = workbook.getSheetAt(0);
            if (sheet == null) {
                throw new JeecgBootException("Excel文件中没有找到工作表");
            }

            // 获取表头行
            Row headerRow = sheet.getRow(0);
            if (headerRow == null) {
                throw new JeecgBootException("Excel文件中没有找到表头行");
            }


            // 检查表头行是否对照  入库单号供应商系列材料名称编码颜色颜色编码厚度框型编码产地支长支重仓位入库数量入库总量入库方式金额备注合同号
            //拼接表头行0-17列
            String headerRowString = "";
            for (int i = 0; i < headerRow.getLastCellNum(); i++) {
                headerRowString = headerRowString + headerRow.getCell(i).getStringCellValue();
            }
            if (!headerRowString.equals("入库单号供应商系列材料名称编码颜色颜色编码厚度框型编码产地支长支重仓位入库数量入库总量入库方式金额备注合同号")) {
                throw new JeecgBootException("Excel文件中的表头行与期望的列名不匹配");
            }

            // 定义期望的列名映射  入库单号（索引0）、系列（索引2）、物料名称（3）、物料编码（4）、物料颜色（5）、物料长度（10）、入库数量（13）、订单编号（18）
            Map<String, String> columnMapping = new HashMap<>();
            columnMapping.put("入库单号", "inboundNo");
            columnMapping.put("系列", "series");
            columnMapping.put("材料名称", "materialName");
            columnMapping.put("编码", "materialCode");
            columnMapping.put("颜色", "materialColor");
            columnMapping.put("支长", "materialLength");
            columnMapping.put("入库数量", "inboundQuantity");
            columnMapping.put("合同号", "orderNo");
            columnMapping.put("入库方式", "unit");

            // 解析表头，建立列索引映射
            Map<String, Integer> columnIndexMap = new HashMap<>();
            for (int i = 0; i < headerRow.getLastCellNum(); i++) {
                Cell cell = headerRow.getCell(i);
                if (cell != null) {
                    String headerValue = getCellStringValue(cell).trim();
                    if (columnMapping.containsKey(headerValue)) {
                        columnIndexMap.put(columnMapping.get(headerValue), i);
                    }
                }
            }


            // 解析数据行
            for (int rowIndex = 1; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
                Row row = sheet.getRow(rowIndex);
                if (row == null) {
                    continue;
                }

                // 检查是否为空行
                boolean isEmptyRow = true;
                for (int i = 0; i < row.getLastCellNum(); i++) {
                    Cell cell = row.getCell(i);
                    if (cell != null && StringUtils.isNotBlank(getCellStringValue(cell))) {
                        isEmptyRow = false;
                        break;
                    }
                }

                if (isEmptyRow) {
                    continue;
                }

                Map<String, Object> rowData = new HashMap<>();

                // 解析各列数据
                for (Map.Entry<String, Integer> entry : columnIndexMap.entrySet()) {
                    String fieldName = entry.getKey();
                    Integer columnIndex = entry.getValue();

                    Cell cell = row.getCell(columnIndex);
                    String cellValue = getCellStringValue(cell);

                    if ("inboundQuantity".equals(fieldName)) {
                        // 入库数量需要转换为数字
                        try {
                            if (StringUtils.isNotBlank(cellValue)) {
                                BigDecimal quantity = new BigDecimal(cellValue);
                                rowData.put(fieldName, quantity);
                            }
                        } catch (NumberFormatException e) {
                            log.warn("第{}行入库数量格式错误: {}", rowIndex + 1, cellValue);
                            rowData.put(fieldName, BigDecimal.ZERO);
                        }
                    } else {
                        rowData.put(fieldName, cellValue);
                    }
                }

                // 验证必需字段
                String materialCode = (String) rowData.get("materialCode");
                String materialName = (String) rowData.get("materialName");
                BigDecimal inboundQuantity = (BigDecimal) rowData.get("inboundQuantity");

                if (StringUtils.isBlank(materialCode) || StringUtils.isBlank(materialName) ||
                        inboundQuantity == null || inboundQuantity.compareTo(BigDecimal.ZERO) <= 0) {
                    log.warn("第{}行数据不完整，跳过: 物料编码={}, 物料名称={}, 入库数量={}",
                            rowIndex + 1, materialCode, materialName, inboundQuantity);
                    continue;
                }

                //根据materialCode获取余料绑定库位的情况
                List<WmsWarehouseLocation> materialCodeList = wmsWarehouseLocationService.list(new QueryWrapper<WmsWarehouseLocation>()
                        .like("material_code_list", materialCode + ","));

                if (materialCodeList.size() > 0) {
                    WmsWarehouseLocation location = wmsWarehouseLocationService.getById(materialCodeList.get(0).getId());
                    rowData.put("locationId", location.getId());
                    rowData.put("locationName", location.getLocationName());
                    rowData.put("locationCode", location.getLocationCode());
                    rowData.put("warehouseId", location.getWarehouseId());
                    WmsWarehouse warehouse = wmsWarehouseService.getById(location.getWarehouseId());
                    rowData.put("warehouseName", warehouse.getWarehouseName());
                    rowData.put("warehouseCode", warehouse.getWarehouseCode());
                }

                result.add(rowData);
            }

            workbook.close();

        } catch (Exception e) {
            log.error("解析Excel文件失败", e);
            throw new JeecgBootException("解析Excel文件失败: " + e.getMessage());
        }

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveRemainingMaterialInboundFromImport(List<Map<String, Object>> dataList, String createBy, String createByName) {
        try {
            // 按入库单号分组数据
            Map<String, List<Map<String, Object>>> groupedData = dataList.stream()
                    .collect(Collectors.groupingBy(data -> {
                        String inboundNo = (String) data.get("inboundNo");
                        return StringUtils.isNotBlank(inboundNo) ? inboundNo : "DEFAULT";
                    }));

            for (Map.Entry<String, List<Map<String, Object>>> entry : groupedData.entrySet()) {
                String inboundNo = entry.getKey();
                List<Map<String, Object>> materials = entry.getValue();

                // 如果没有指定入库单号，生成一个新的
                if ("DEFAULT".equals(inboundNo)) {
                    inboundNo = generateInboundNoByBusinessType(12); // 12为余料入库业务类型
                }


                //根据入库单号查询，确保入库单号唯一
                Long count = this.count(new QueryWrapper<WmsInboundOrder>().eq("inbound_no", inboundNo));
                if (count > 0) {
                    throw new JeecgBootException("当前入库单号已存在，请确保入库单号唯一");
                }
                // 创建入库单主记录
                WmsInboundOrder inboundOrder = new WmsInboundOrder();
                inboundOrder.setInboundNo(inboundNo);
                inboundOrder.setBusinessType(12); // 余料入库
                inboundOrder.setIsSurplus(true);
                inboundOrder.setStatus(1); // 待入库
                inboundOrder.setPlanInboundTime(new Date());
                inboundOrder.setRemark("Excel导入的余料入库单");

                // 计算总计划数量
                BigDecimal totalPlanQuantity = materials.stream()
                        .map(data -> BigDecimal.valueOf(Integer.valueOf(data.get("inboundQuantity").toString())))
                        .filter(Objects::nonNull)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);

                inboundOrder.setTotalPlanQuantity(totalPlanQuantity);

                // 从第一条记录中获取订单编号作为业务单号
                String orderNo = (String) materials.get(0).get("orderNo");
                if (StringUtils.isNotBlank(orderNo)) {
                    inboundOrder.setBusinessNo(orderNo);
                }

                // 生成批次号
                String batchNo = "PC" + String.format("%tY%<tm%<td", new Date()) +
                        String.format("%04d", (int) (Math.random() * 10000));
                inboundOrder.setBatchNo(batchNo);

                // 保存入库单主记录
                this.save(inboundOrder);

                // 创建入库单明细
                for (Map<String, Object> materialData : materials) {
                    WmsInboundOrderDetail detail = new WmsInboundOrderDetail();
                    detail.setInboundOrderId(inboundOrder.getId());
                    detail.setMaterialCode((String) materialData.get("materialCode"));
                    detail.setMaterialName((String) materialData.get("materialName"));
                    detail.setPlanQuantity(BigDecimal.valueOf(Integer.valueOf(materialData.get("inboundQuantity").toString())));
                    detail.setActualQuantity(BigDecimal.ZERO);
                    detail.setInboundStatus("0"); // 待入库
                    detail.setMaterialSeries(materialData.get("series").toString());
                    detail.setColor((String) materialData.get("materialColor"));
                    detail.setMaterialLength(BigDecimal.valueOf(Double.valueOf(materialData.get("materialLength").toString())));
                    detail.setPlanWarehouseId((String) materialData.get("warehouseId"));
                    detail.setPlanWarehouseName((String) materialData.get("warehouseName"));
                    detail.setPlanLocationId((String) materialData.get("locationId"));
                    detail.setPlanLocationName((String) materialData.get("locationName"));
                    detail.setMaterialType("5");
                    detail.setUnit((String) materialData.get("unit"));

                    detailService.save(detail);
                }
            }

            return true;

        } catch (Exception e) {
            log.error("保存余料入库单导入数据失败", e);
            throw new JeecgBootException("保存导入数据失败: " + e.getMessage());
        }
    }

    /**
     * 获取单元格字符串值
     */
    private String getCellStringValue(Cell cell) {
        if (cell == null) {
            return "";
        }

        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue();
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    return new SimpleDateFormat("yyyy-MM-dd").format(cell.getDateCellValue());
                } else {
                    // 避免科学计数法
                    double numericValue = cell.getNumericCellValue();
                    if (numericValue == (long) numericValue) {
                        return String.valueOf((long) numericValue);
                    } else {
                        return String.valueOf(numericValue);
                    }
                }
            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            case FORMULA:
                try {
                    return cell.getStringCellValue();
                } catch (Exception e) {
                    return String.valueOf(cell.getNumericCellValue());
                }
            default:
                return "";
        }
    }

    /**
     * 获取列的中文名称
     */
    private String getChineseColumnName(String fieldName) {
        switch (fieldName) {
            case "inboundNo":
                return "入库单号";
            case "series":
                return "系列";
            case "materialName":
                return "物料名称";
            case "materialCode":
                return "物料编码";
            case "materialColor":
                return "物料颜色";
            case "materialLength":
                return "物料长度";
            case "inboundQuantity":
                return "入库数量";
            case "orderNo":
                return "订单编号";
            default:
                return fieldName;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean oneClickInbound(String inboundOrderId, String realname) {
        try {

            // 1. 获取入库单信息
            WmsInboundOrder inboundOrder = this.getById(inboundOrderId);
            if (inboundOrder == null) {
                log.error("入库单不存在，ID: {}", inboundOrderId);
                throw new JeecgBootException("入库单不存在");
            }

            // 2. 检查入库单状态
            if (inboundOrder.getStatus() != 1) {
                log.error("入库单状态不正确，当前状态: {}", inboundOrder.getStatus());
                throw new JeecgBootException("只有待入库状态的入库单才能执行一键入库");
            }

            // 3. 检查是否为余料入库单
            if (inboundOrder.getBusinessType() != 12) {
                log.error("非余料入库单不能执行一键入库，业务类型: {}", inboundOrder.getBusinessType());
                throw new JeecgBootException("只有余料入库单才能执行一键入库");
            }

            // 4. 获取入库单明细
            List<WmsInboundOrderDetail> detailList = detailService.list(
                    new LambdaQueryWrapper<WmsInboundOrderDetail>()
                            .eq(WmsInboundOrderDetail::getInboundOrderId, inboundOrderId)
            );

            if (detailList.isEmpty()) {
                log.error("入库单明细为空，入库单ID: {}", inboundOrderId);
                throw new JeecgBootException("入库单明细为空，无法执行入库");
            }

            Date now = new Date();
            BigDecimal totalActualQuantity = BigDecimal.ZERO;

            // 5. 处理每个明细项
            for (WmsInboundOrderDetail detail : detailList) {
                // 设置实际入库数量等于计划入库数量
                detail.setActualQuantity(detail.getPlanQuantity());
                detail.setInboundStatus("1"); // 已入库

                totalActualQuantity = totalActualQuantity.add(detail.getPlanQuantity());

                // 6. 创建或更新库存记录
                createOrUpdateInventory(detail, inboundOrder, realname, now);
            }

            // 7. 批量更新明细
            detailService.updateBatchById(detailList);

            // 8. 更新入库单状态
            inboundOrder.setStatus(2); // 已入库
            inboundOrder.setTotalActualQuantity(totalActualQuantity);
            inboundOrder.setActualInboundTime(now);

            this.updateById(inboundOrder);

            log.info("一键入库完成，入库单号: {}, 总入库数量: {}", inboundOrder.getInboundNo(), totalActualQuantity);
            return true;

        } catch (Exception e) {
            log.error("一键入库失败，入库单ID: {}", inboundOrderId, e);
            throw new JeecgBootException("一键入库失败: " + e.getMessage());
        }
    }

    /**
     * 创建或更新库存记录
     */
    private void createOrUpdateInventory(WmsInboundOrderDetail detail, WmsInboundOrder inboundOrder, String realname, Date now) {
        try {
            // 查找是否已存在库存记录  根据物料编号-颜色-长度-仓库-库位
            WmsInventory existingInventory = wmsInventoryService.getOne(
                    new LambdaQueryWrapper<WmsInventory>()
                            .eq(WmsInventory::getMaterialCode, detail.getMaterialCode())
                            .eq(WmsInventory::getColor, detail.getColor())
                            .eq(WmsInventory::getMaterialLength, detail.getMaterialLength())
                            .eq(WmsInventory::getWarehouseId, detail.getPlanWarehouseId())
                            .eq(WmsInventory::getLocationId, detail.getPlanLocationId())
                            .last("LIMIT 1")
            );

            if (existingInventory != null) {
                // 记录变动前数量
                BigDecimal beforeQuantity = existingInventory.getQuantity();
                BigDecimal beforeAvailableQuantity = existingInventory.getAvailableQuantity();

                // 更新现有库存
                BigDecimal newQuantity = existingInventory.getQuantity().add(detail.getPlanQuantity());
                existingInventory.setQuantity(newQuantity);
                //更新可用数量
                BigDecimal newAvailableQuantity = existingInventory.getAvailableQuantity().add(detail.getPlanQuantity());
                existingInventory.setAvailableQuantity(newAvailableQuantity);
                wmsInventoryService.updateById(existingInventory);

                // 记录库存历史
                wmsInventoryHistoryService.recordHistory(
                        existingInventory,
                        beforeQuantity,
                        detail.getPlanQuantity(),
                        newQuantity,
                        inboundOrder.getBusinessType(),
                        inboundOrder.getInboundNo(),
                        realname,
                        inboundOrder.getInboundNo() + " " + DateUtils.formatDateTime() + " 一键入库-更新库存"
                );

                log.debug("更新库存记录，物料: {}, 变动前数量: {}, 变动数量: {}, 新数量: {}",
                        detail.getMaterialCode(), beforeQuantity, detail.getPlanQuantity(), newQuantity);
            } else {
                // 创建新库存记录
                WmsInventory newInventory = new WmsInventory();
                newInventory.setMaterialCode(detail.getMaterialCode());
                newInventory.setMaterialName(detail.getMaterialName());
                newInventory.setWarehouseId(detail.getPlanWarehouseId());
                newInventory.setLocationId(detail.getPlanLocationId());
                newInventory.setQuantity(detail.getPlanQuantity());
                newInventory.setAvailableQuantity(detail.getPlanQuantity());
                newInventory.setMaterialType(Integer.valueOf(detail.getMaterialType()));
                newInventory.setColor(detail.getColor());
                newInventory.setMaterialLength(detail.getMaterialLength());
                newInventory.setMaterialSeries(detail.getMaterialSeries());
                newInventory.setUnit(detail.getUnit());
                newInventory.setBatchNo(inboundOrder.getBatchNo());

                wmsInventoryService.save(newInventory);

                // 记录库存历史（新建库存）
                wmsInventoryHistoryService.recordHistory(
                        newInventory,
                        BigDecimal.ZERO,
                        detail.getPlanQuantity(),
                        detail.getPlanQuantity(),
                        inboundOrder.getBusinessType(),
                        inboundOrder.getInboundNo(),
                        realname,
                        inboundOrder.getInboundNo() + " " + DateUtils.formatDateTime() + " 一键入库-新建库存"
                );

                log.debug("创建库存记录，物料: {}, 数量: {}", detail.getMaterialCode(), detail.getPlanQuantity());
            }

        } catch (Exception e) {
            log.error("创建或更新库存记录失败，物料: {}", detail.getMaterialCode(), e);
            throw new JeecgBootException("创建或更新库存记录失败: " + e.getMessage());
        }
    }
}